完成個人檔案頁面後,但好像少了些什麼?
啊!使用者沒有大頭貼啦
我們就來做圖片上傳功能吧!
Rails 有個好用的圖片上傳功能,叫做 Active Storage
我們會搭配 Active Storage 以及 S3 來做
一樣請依照官方來安裝所需要的套件 image_processing
以及 active_storage
特別說明一下,安裝完 active_storage
後,會產出 active_storage_blobs
active_storage_variant_records
active_storage_attachments
這三個 table
稍微介紹一下他們個別的作用:
active_storage_blobs
會存放檔案的基本資訊,例如檔案名稱、存放的 server、檔案大小、檔案格式
active_storage_variant_records
處理檔案的各種不同 size 及格式
active_storage_attachments
使用 polymorphic 的方式來記錄檔案是屬於哪個 model 的
我們這次使用的是 amazon 的 S3 服務,所以就把 amazon 註解區塊解除掉
# storage.yml
amazon:
service: S3
access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
region: us-east-1
bucket: your_own_bucket-<%= Rails.env %>
要使用 S3 服務,我們就必須去註冊一個 amazon 的帳號密碼,並且取得 key 的資料
Bucket name
填寫名字AWS Region
指的是伺服器位置,可以選擇你習慣用的
ACLs enabled - 只有此帳號才可以存取這個物件(較嚴謹),不過選擇這個的話,三不五時就會需要 token 來驗證,應該會非常困擾
ACLs disabled - 其他用戶都可以存取這個物件
在上一步我們將物件開放給其他用戶存取,不過在這個區塊我們可以來阻擋一些權限,來增加一點安全性
Block public access to buckets and objects granted through new access control lists (ACLs): 阻擋新的 ACLs 存取權
Block public access to buckets and objects granted through any access control lists (ACLs):阻擋所有 ACLs 存取權
Block public access to buckets and objects granted through new public bucket or access point policies:只有授權的人才能存取
Block public and cross-account access to buckets and objects through any public bucket or access point policies:禁止跨帳戶存取
我們只要勾下面三項就好,最後勾選免責聲明書?
接下來都套用預設就好了,我們就可以到下一步了
創建成功後,我們必須要來設定 S3 檔案的權限
點選 Policies
右邊有個 create policy 藍色按鈕,點下去
我們要設定的是 S3 ,就選擇 S3
接下來我們就要設定用戶可以針對物件做些什麼事情(可以參考 Rails 建議設定)
讓用戶可以存取到圖片,所以要選擇 List 中的 ListBucket
讓用戶可以讀取圖片,所以要選擇 Read 中 GetObject
讓用戶可以上傳圖片,所以選擇 Write 中 PutObject
接下來是要讓所有人都可以存取,需要給他 ACL 存取,選擇 Permissions management 中的 PutObjectAcl
下方要指定 bucket 給他,在 bucket 這個地方選擇 Add Arn
接下來要設定 bucket 哪些檔案套用上方的 policy
點選下一步後,填寫名稱就建立完成了
設定完 Policy 後,我們要來設定 User,並且拿取 key
我們到 IAM 底下的 User
右方有個橘色 create user 的按鈕,點選下去
幫 user 命名後點選下一步
在這邊我們要設定 policy 給這個 user,所以點選 Attach policies directly
接下來在 Permission policies 搜尋剛剛你做的 policy 的名字
選取後下一步,沒有額外要設定的話就可以直接 create user 了
user 建立後,我們可以點選進去,選擇 security credentials
到 Access keys 區塊,點選 Create access key
選擇 Application running outside AWS,
點選下一步後,再點選 create 就可以囉
設定成 amazon 後,他就會去 storage.yml 檔案中找 amazon 的設定
# config/environments/development.rb
config.active_storage.service = :amazon
設定完也要記得更新 storage.yml 喔
應該只要更新 access_key_id 及 secret_access_key 及 bucket
這邊的環境變數是使用預設的 master.key 來存取(若你是使用 master.key 就可以沿用)
如果是使用 dotenv 來存取環境變數,就必須改寫法
# config/storage.yml
service: S3
access_key_id: <%= ENV['AMAZON_ACCESS_KEY'] %>
secret_access_key: <%= ENV['AMAZON_SECRET_ACCESS_KEY'] %>
region: us-east-1
bucket: test-sideproject
AWS 提供的工具,讓我們可在應用程式中使用 S3
gem "aws-sdk-s3", require: false
因為是跨網存取服務,我們必須要在 S3 中設定,不然就會被 Rails 擋下
到 S3 > bucket > 點選你的 bucket > Permissions
拉到最下面會有個 CORS 區塊,點選 edit,並將這串貼上修改
AllowedHeaders
: 哪些 Header 是被允許的
AllowedMethods
: 哪些 HTTP 方法(GET、POST、PUT、DELETE等)被允許用來訪問 S3
AllowedOrigins
: 哪些網域被允許訪問 S3
ExposeHeaders
: 指定哪些 Header 會放在回應中,讓前端 JavaScript 程式碼可以訪問這些 Header
MaxAgeSeconds
: 瀏覽器應該將 CORS 規則緩存多長時間,在這個時間內,瀏覽器不需要對同一個資源發出另一個請求
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"PUT"
],
"AllowedOrigins": [
"https://127.0.0.1:3000"
],
"ExposeHeaders": [
"Origin",
"Content-Type",
"Content-MD5",
"Content-Disposition"
],
"MaxAgeSeconds": 3600
}
]
設定完即可存檔
在個人檔案的 model 中加入 has_one_attached
# app/modle/profile.rb
class Profile < ApplicationRecord
belongs_to :user
has_one_attached :avatar
end
接著我們可以到昨天做的 component 中,把大頭貼的欄位塞進去
# app/components/profile_form_component.html.erb
<div class="flex items-center mb-4 field">
<%= f.label :avatar, '大頭貼' , class: 'mr-4' %><br />
<%= f.file_field :avatar, class: 'rounded-md' %>
</div>
接下來到 controller 中,在 params 裡面也要記得加入
# app/controllers/profiles_controller.rb
def profile_params
params.require(:profile).permit(:name, :address, :phone, :gender, :birthday, :avatar).merge(user: current_user)
end
因為我們剛剛做了蠻多設定上的調整,所以重開 server
送出之後應該就成功囉
今天篇幅比較長,在 view 裡面的存取就另一篇再說吧!